package hexxagon;

import ai.GameBoard;
import ai.Move;
import ai.Piece;
import jgame.JGColor;
import jgame.JGFont;
import jgame.JGPoint;
import jgame.platform.StdGame;

/**
 * Game display
 */
public class Hexxagon extends StdGame {

    private GameBoard gameBoard = null;
    public static final int GREEN = 4;
    public static final int YELLOW = 5;
    private static final int GOC_XI = 33;
    private static final int GOC_YI = 139;
    private static final int TRUE_X = 30;
    private static final int TRUE_Y = 140;
    public static JGPoint IndexToPos = new JGPoint();
    public static JGPoint PosToIndex = new JGPoint();
    private static boolean picked = false;
    private static int pickedAtX = -1;
    private static int pickedAtY = -1;
    private static int moveToX = -1;
    private static int moveToY = -1;
    private static double lastTimeClick = 0;
    public boolean moved = false;
    private int depth = 3;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Hexxagon(new JGPoint(800, 600));
    }

    public Hexxagon(JGPoint size) {
        initEngine(size.x, size.y);
    }

    @Override
    public void initCanvas() {
        setCanvasSettings(1, 1, 800, 600, JGColor.cyan, JGColor.black,
                new JGFont("Times New Roman", JGFont.ITALIC, 30));
    }

    @Override
    public void initGame() {
        setFrameRate(40, 2);
        defineMedia("hexxagon.tbl");
        setBGImage("background");
        setStatusDisplay(new JGFont("Times New Roman", JGFont.ITALIC | JGFont.BOLD, 20),
                JGColor.green, "piece_0");

        setAuthorMessage("Hanoi University of Technology, School of Infomation Technology and Communication");
        setGameState("Title");
        lives = 1000;
        leveldone_ticks = 10;
        startgame_ticks = 20;
    }

    @Override
    public void doFrame() {
        super.doFrame();
        moveObjects();
        if (inGameState("InGame")) {
            if (timer - lastTimeClick > 50) {
                removeObjects("cu", 0);
            }
            if (!gameBoard.isEndGame()) {
                revertPosToIndex(getMouseX(), getMouseY());
                if (gameBoard.getCurrentPlayer() == Piece.HUMAN && getMouseButton(1) && (timer - lastTimeClick > 20)) {
                    humanMove(getMouseX(), getMouseY());
                    lastTimeClick = timer;
                }
                if (gameBoard.getCurrentPlayer() == Piece.COMPUTER && (timer - lastTimeClick > 5)) {
                    setMouseCursor(WAIT_CURSOR);
                    computerMove();
                    setMouseCursor(HAND_CURSOR);
                }
            } else {
                setGameState("LifeLost");
            }
        }
    }

    @Override
    public void paintFrameLifeLost(){
        if (gameBoard.countPieces[Piece.COMPUTER] == gameBoard.countPieces[Piece.HUMAN]) {
            drawString("Hoà!", viewWidth() / 2, viewHeight() / 3, 0,
                    new JGFont("Times New Roman", JGFont.ITALIC | JGFont.BOLD, 20), JGColor.green);
        } else if (gameBoard.countPieces[Piece.HUMAN] > gameBoard.countPieces[Piece.COMPUTER]) {
            drawString("Chúc mừng, bạn đã thắng!", viewWidth() / 2, viewHeight() / 3, 0,
                    new JGFont("Times New Roman", JGFont.ITALIC | JGFont.BOLD, 20), JGColor.green);
        } else {
            drawString("Rất tiếc, bạn đã thua!", viewWidth() / 2, viewHeight() / 3, 0,
                    new JGFont("Times New Roman", JGFont.ITALIC | JGFont.BOLD, 20), JGColor.green);
        }
    }

    //write pieces of each player on top of window
    @Override
    public void paintFrame() {
        setFont(status_font);
        setColor(status_color);

        if (gameBoard != null) {
            drawImage(0, 0, "piece_" + Piece.HUMAN);
            drawString("You", 100, 10, 0, status_font, JGColor.cyan);
            drawString(Integer.toString(gameBoard.countPieces[Piece.HUMAN]), 100, 30, -1, status_font, JGColor.cyan);

            drawImage(getWidth() - 80, 0, "piece_" + Piece.COMPUTER);
            drawString("Com", getWidth() - 100, 10, 0, status_font, JGColor.red);
            drawString(Integer.toString(gameBoard.countPieces[Piece.COMPUTER]), getWidth() - 100, 30, 1, status_font, JGColor.red);

            drawString((gameBoard.getCurrentPlayer() == Piece.HUMAN ? "Your turn, picked = " + picked + " " + pickedAtX + ":" + pickedAtY : "Com turn"), 0, 580, -1);
        }

        drawString("depth search = " + depth, 0, 560, -1, status_font, status_color);
        drawString("screen " + getMouseX() + ":" + getMouseY(), getWidth() - 150, 560, -1, status_font, status_color);
        revertPosToIndex(getMouseX(), getMouseY());
        drawString("index " + (isValid(PosToIndex.x, PosToIndex.y) ? (PosToIndex.x + ":" + PosToIndex.y) : "not valid"),
                getWidth() - 240, 580, -1, status_font, status_color);
        drawString("timer = " + (int) timer / 100, getWidth() - 100, 580, -1, status_font, JGColor.cyan);
    }

    public void doFrameTitle() {
    }

    @Override
    public void initNewLife() {
        removeObjects(null, 0);
        gameBoard = new GameBoard();
    }

    @Override
    public void startGameOver() {
        removeObjects(null, 0);
        gameBoard = new GameBoard();
    }

    //paint when game starts
    @Override
    public void paintFrameStartGame() {
        drawString("Good luck!",
                viewWidth() / 2, viewHeight() / 3, 0, title_font, title_color);
        setMouseCursor(HAND_CURSOR);
        lastTimeClick = timer + 100;
    }

    @Override
    public void paintFrameStartLevel() {
        if (gameBoard == null) {
            gameBoard = new GameBoard();
        }
    }

    @Override
    public void paintFrameTitle() {
        drawString("BÀI TẬP LỚN MÔN TRÍ TUỆ NHÂN TẠO", viewWidth() / 2, 5 * viewHeight() / 20, 0,
                new JGFont("Arial", JGFont.BOLD | JGFont.PLAIN, 25), JGColor.green);
        drawString("ĐỀ TÀI: TRÒ CHƠI CỜ GÁNH \"HEXXAGON\"", viewWidth() / 2, 6 * viewHeight() / 20, 0,
                new JGFont("Arial", JGFont.BOLD | JGFont.PLAIN, 25), JGColor.green);
        drawString("Ấn " + getKeyDesc(key_startgame) + " để bắt đầu", viewWidth() / 2, 14 * viewHeight() / 20, 0,
                new JGFont("Courier New", JGFont.BOLD | JGFont.ITALIC, 25), JGColor.cyan);
    }

    /**
     * translate from index to Point on screen
     * @param x x-index
     * @param y y-index
     * @return A point on screen
     */
    public static void translateIndexToPos(int x, int y) {
        IndexToPos.x = (int) (GOC_XI + x * 81.75);
        IndexToPos.y = (int) (GOC_YI + y * 65 - x * 32.5);
    }

    public static boolean revertPosToIndex(int x, int y) {
        float xF = (x - TRUE_X) / 81.75f;
        float yF = (y - TRUE_Y + (int) xF * 32.5f) / 65;
        if (isValid((int) xF, (int) yF) && xF >= 0 && yF >= 0) {
            PosToIndex.x = (int) xF;
            PosToIndex.y = (int) yF;
            return true;
        } else {
            PosToIndex.x = -1;
            PosToIndex.y = -1;
        }
        return false;
    }

    public static boolean isValid(int x, int y) {
        if ((x == 3 && y == 4) || (x == 4 && y == 3) || (x == 5 && y == 5)) {
            return false;
        }
        if ((x == 0 && y > 4) || (x == 1 && y > 5) || (x == 2 && y > 6) || (x == 3 && y > 7)
                || (x == 5 && y < 1) || (x == 6 && y < 2) || (x == 7 && y < 3) || (x == 8 && y < 4)) {
            return false;
        }
        if (x < 0 || x > 8 || y < 0 || y > 8) {
            return false;
        }
        return true;
    }

    public void humanMove(int xPixel, int yPixel) {
        removeObjects("cu", 0);
        if (revertPosToIndex(xPixel, yPixel)) {
            if (!picked) {
                if (isValid(PosToIndex.x, PosToIndex.y)
                        && gameBoard.getBoard()[PosToIndex.x][PosToIndex.y].getStatus() == Piece.HUMAN) {
                    pickedAtX = PosToIndex.x;
                    pickedAtY = PosToIndex.y;
                    picked = true;
                    if (!displayFigures(pickedAtX, pickedAtY)){
                        picked = false;
                    }
                }
            } else {
                moveToX = PosToIndex.x;
                moveToY = PosToIndex.y;

                if (moveToX == pickedAtX && moveToY == pickedAtY) {
                    picked = false;
                    pickedAtX = -1;
                    pickedAtY = -1;
                    removeFigures();
                    return;
                }

                if (gameBoard.getBoard()[moveToX][moveToY].getStatus() == Piece.HUMAN) {
                    removeFigures();
                    pickedAtX = moveToX;
                    pickedAtY = moveToY;
                    picked = true;
                    if (!displayFigures(pickedAtX, pickedAtY)) {
                        picked = false;
                    }
                    return;
                }

                if (gameBoard.isValidMove(gameBoard.getBoard()[pickedAtX][pickedAtY], gameBoard.getBoard()[moveToX][moveToY])) {
                    gameBoard.move(gameBoard.getBoard()[pickedAtX][pickedAtY], gameBoard.getBoard()[moveToX][moveToY]);
                    gameBoard.setCurrentPlayer(Piece.COMPUTER);
                }
                picked = false;
                pickedAtX = -1;
                pickedAtY = -1;
                removeFigures();
            }
        }
    }//Method

    public void computerMove() {
        GameBoard board = gameBoard.copyBoard();
        int alphabeta = gameBoard.alphaBetaPrunning(board, depth, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
        System.out.println("alphabeta = " + alphabeta + "\nprunned " + GameBoard.prunned
                + "\ncall " + GameBoard.call + " times");
        Move bestMove = gameBoard.getBestMove();
        if (bestMove != null) {
            new Figure(bestMove.getPFrom().getX(), bestMove.getPFrom().getY());
            new Figure(bestMove.getPTo().getX(), bestMove.getPTo().getY());
            gameBoard.move(bestMove.getPFrom(), bestMove.getPTo());
            gameBoard.setCurrentPlayer(Piece.HUMAN);
        } else {
            System.out.println("No best move found");
        }
    }

    public boolean displayFigures(int x, int y) {
        boolean hasFigureB = false;

        if (isValid(x, y - 1) && gameBoard.getBoard()[x][y - 1].getStatus() == Piece.EMPTY) {
            new Figure(x, y - 1, 1);
            hasFigureB = true;
        }
        if (isValid(x, y + 1) && gameBoard.getBoard()[x][y + 1].getStatus() == Piece.EMPTY) {
            new Figure(x, y + 1, 1);
            hasFigureB = true;
        }
        if (isValid(x - 1, y - 1) && gameBoard.getBoard()[x - 1][y - 1].getStatus() == Piece.EMPTY) {
            new Figure(x - 1, y - 1, 1);
            hasFigureB = true;
        }
        if (isValid(x + 1, y + 1) && gameBoard.getBoard()[x + 1][y + 1].getStatus() == Piece.EMPTY) {
            new Figure(x + 1, y + 1, 1);
            hasFigureB = true;
        }
        if (isValid(x - 1, y) && gameBoard.getBoard()[x - 1][y].getStatus() == Piece.EMPTY) {
            new Figure(x - 1, y, 1);
            hasFigureB = true;
        }
        if (isValid(x + 1, y) && gameBoard.getBoard()[x + 1][y].getStatus() == Piece.EMPTY) {
            new Figure(x + 1, y, 1);
            hasFigureB = true;
        }

        if (isValid(x - 2, y - 2) && gameBoard.getBoard()[x - 2][y - 2].getStatus() == Piece.EMPTY) {
            new Figure(x - 2, y - 2, 2);
            hasFigureB = true;
        }
        if (isValid(x + 2, y + 2) && gameBoard.getBoard()[x + 2][y + 2].getStatus() == Piece.EMPTY) {
            new Figure(x + 2, y + 2, 2);
            hasFigureB = true;
        }
        if (isValid(x - 2, y - 1) && gameBoard.getBoard()[x - 2][y - 1].getStatus() == Piece.EMPTY) {
            new Figure(x - 2, y - 1, 2);
            hasFigureB = true;
        }
        if (isValid(x + 2, y + 1) && gameBoard.getBoard()[x + 2][y + 1].getStatus() == Piece.EMPTY) {
            new Figure(x + 2, y + 1, 2);
            hasFigureB = true;
        }
        if (isValid(x - 2, y) && gameBoard.getBoard()[x - 2][y].getStatus() == Piece.EMPTY) {
            new Figure(x - 2, y, 2);
            hasFigureB = true;
        }
        if (isValid(x + 2, y) && gameBoard.getBoard()[x + 2][y].getStatus() == Piece.EMPTY) {
            new Figure(x + 2, y, 2);
            hasFigureB = true;
        }
        if (isValid(x - 1, y + 1) && gameBoard.getBoard()[x - 1][y + 1].getStatus() == Piece.EMPTY) {
            new Figure(x - 1, y + 1, 2);
            hasFigureB = true;
        }
        if (isValid(x + 1, y - 1) && gameBoard.getBoard()[x + 1][y - 1].getStatus() == Piece.EMPTY) {
            new Figure(x + 1, y - 1, 2);
            hasFigureB = true;
        }
        if (isValid(x, y + 2) && gameBoard.getBoard()[x][y + 2].getStatus() == Piece.EMPTY) {
            new Figure(x, y + 2, 2);
            hasFigureB = true;
        }
        if (isValid(x, y - 2) && gameBoard.getBoard()[x][y - 2].getStatus() == Piece.EMPTY) {
            new Figure(x, y - 2, 2);
            hasFigureB = true;
        }
        if (isValid(x + 1, y + 2) && gameBoard.getBoard()[x + 1][y + 2].getStatus() == Piece.EMPTY) {
            new Figure(x + 1, y + 2, 2);
            hasFigureB = true;
        }
        if (isValid(x - 1, y - 2) && gameBoard.getBoard()[x - 1][y - 2].getStatus() == Piece.EMPTY) {
            new Figure(x - 1, y - 2, 2);
            hasFigureB = true;
        }
        if(hasFigureB){
            new Figure(x, y, 2);
            return true;
        }
        return false;
    }

    public void removeFigures() {
        removeObjects("f", 0);
    }
}
